﻿using System.Collections.Generic;
using System.IO;
using System.Linq;

using Microsoft.Xna.Framework.Graphics;
using SceneEngine;
using System.ComponentModel;

namespace SceneEditor
{
    /// <summary>
    /// Stores a list of all of the available models.
    /// </summary>
    public class ModelManager
    {
        private Dictionary<string, Model> models =
            new Dictionary<string, Model>();

        private Dictionary<string, string> newTexturePaths =
            new Dictionary<string, string>();

        /// <summary>
        /// Returns a list of the available models.
        /// </summary>
        public Dictionary<string, Model> Models
        {
            get { return models; }
        }

        /// <summary>
        /// Constructs a new AssetManager object.
        /// </summary>
        public ModelManager(BackgroundWorker worker)
        {
            EditorGlobals.ModelManager = this;

            string directory = Path.Combine(EditorGlobals.ContentPath, "Models");

            List<string> modelPaths = EditorGlobals.FindAllFiles(directory);

            for (int i = 0; i < modelPaths.Count; i++)
            {
                if (!modelPaths[i].ToLower().Contains(".fbx") && 
                    !modelPaths[i].ToLower().Contains(".x"))
                {
                    modelPaths.RemoveAt(i);
                    i -= 1;

                    continue;
                }
                else
                {
                    if (modelPaths[i].ToLower().Contains(".fbx"))
                    {
                        modelPaths[i] = modelPaths[i].Remove(modelPaths[i].Length - 4);
                    }
                    else if (modelPaths[i].ToLower().Contains(".x"))
                    {
                        modelPaths[i] = modelPaths[i].Remove(modelPaths[i].Length - 2);
                    }
                }
            }

            for (int i = 0; i < modelPaths.Count; i++)
            {
                int endIndex = modelPaths[i].IndexOf("Models");
                modelPaths[i] = modelPaths[i].Remove(0, endIndex);

                string path = modelPaths[i];

                try
                {
                    Model model = EngineGlobals.Content.Load<Model>(path);
                    models.Add(modelPaths[i], model);

                    EngineGlobals.RenderManager.AddModel(modelPaths[i], model);
                }
                catch
                {
                    MessageBoxHelper.ShowBuiltFileNotFound();
                }

                worker.ReportProgress((int)((float)i / (float)modelPaths.Count * 100.0f) + 1);
            }
        }

        /// <summary>
        /// Loads all the of built models that can
        /// be found in the specified directory.
        /// </summary>
        public void LoadModelsFromDirectory(string directory, BackgroundWorker worker)
        {
            List<string> files = EditorGlobals.FindAllFiles(directory);

            int counter = 1;

            foreach (string filePath in files)
            {
                string fileName = Path.GetFileNameWithoutExtension(filePath);

                string assetPath = Path.ChangeExtension(filePath.Remove(0, directory.Length + 1), null);

                object model = null;

                try
                {
                    model = EditorGlobals.BuiltContent.Load<object>(assetPath);
                }
                catch
                {
                    System.Windows.Forms.MessageBox.Show(fileName + " could not be loaded.");
                    continue;
                }

                if (model is Model == false)
                {
                    continue;
                }

                if (models.ContainsKey(assetPath))
                {
                    continue;
                }

                models.Add(assetPath, model as Model);
                EngineGlobals.RenderManager.AddModel(assetPath, model as Model);

                CopyTexturesToFolder(assetPath);

                worker.ReportProgress((int)((float)counter / (float)files.Count * 100.0f));
                counter += 1;
            }
        }
        /// <summary>
        /// Copies all of a models textures to the same directory
        /// as the model.
        /// </summary>
        public void CopyTexturesToFolder(string modelName)
        {
            ModelInformation modelInfo = (ModelInformation)models[modelName].Tag;

            for (int i = 0; i < modelInfo.OriginalTexturePaths.Count; i++)
            {
                string directory = Path.GetDirectoryName(modelName);

                string relativePath = Path.GetFullPath(Path.Combine(EditorGlobals.ContentPath, 
                                                                    directory,
                                                                    modelInfo.RelativeTexturePaths[i]));

                if (File.Exists(relativePath))
                {
                    continue;
                }

                if (Directory.Exists(Path.GetDirectoryName(relativePath)) == false)
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(relativePath));
                }

                File.Copy(modelInfo.OriginalTexturePaths[i], relativePath);
                if (newTexturePaths.ContainsKey(modelInfo.OriginalTexturePaths[i]))
                {
                    newTexturePaths[modelInfo.OriginalTexturePaths[i]] = relativePath;
                }
                else
                {
                    newTexturePaths.Add(modelInfo.OriginalTexturePaths[i], relativePath);
                }
            }
        }
        /// <summary>
        /// Removes a model from the list of avaialable models.
        /// </summary>
        public void RemoveModel(string modelName)
        {
            if (models.ContainsKey(modelName))
                models.Remove(modelName);

            EngineGlobals.RenderManager.RemoveModel(modelName);
        }
    }
}
